package dp.mobile.game;

import java.util.ArrayList;
import java.util.HashMap;

import javax.microedition.khronos.opengles.GL10;

import org.w3c.dom.Node;

import android.util.Log;

import dp.mobile.glwrapper.GLTexture;
import dp.mobile.glwrapper.GLTiledTexture;
import dp.mobile.glwrapper.GameRenderer;
import dp.mobile.system.Utilities;
import dp.mobile.system.XMLReader;

public class Sprite {
	private static final String TAG = "Sprite";
	protected class Tint {
		public Tint() {
			mTint	= 0;
			mWait	= 0;
			mTimer	= 0;
			mActive	= true;
		}

		//Public
		public Tint(int tint, long time) {
			//Default
			this();

			//Save data
			mWait	= time;
			mTint	= tint;
		}

		public int getTint()		{	return mTint;		}
		public boolean isActive()	{	return mActive;	}
		
		public void update(long time) {
			//If there's wait
			if (mActive && mWait > 0) {
				//Increase timer
				mTimer += time;

				//If done, deactivate
				if (mTimer >= mWait) mActive = false;
			}
		}

		//members
		protected int		mTint;
		protected long		mWait;
		protected long		mTimer;
		protected boolean	mActive;
	}

	protected Sprite() {
		//Initialize
		mX			= 0;
		mY			= 0;
		mFrame		= 0;
		mDelay		= 0;
		mTimer		= 0;
		mWidth		= 0;
		mHeight		= 0;
		mImages		= null;
		mAnimating	= true;
		mTints			= new ArrayList<Tint>();
		mDeletedTints 	= new ArrayList<Tint>();

		//Check hash table
		if (sTints == null) Sprite.readTintData();
	}

	public Sprite(String image, int row, int column) {
		this(image, 0, 0, row, column, 0);
	}

	public Sprite(String image, int x, int y, int row, int column) {
		this(image, x, y, row, column, 0);
	}

	public Sprite(String image, int xPos, int yPos, int row, int column, long delay) {
		//Default
		this();
		
		GLTexture mainTexture = GameRenderer.instance().allocateTexture(image, true);

		//Set position
		mX = xPos;
		mY = yPos;

		//Create images
		mImages = new GLTiledTexture[row * column];

		//Set width and row
		mWidth	= mainTexture.Width	/ column;
		mHeight	= mainTexture.Height/ row;

		//Splice image
		
		for (int x = 0; x < column; x++)
			for (int y = 0; y < row; y++) {
				final float left 	= (float)x 		/ (float)column;
				final float right 	= (float)(x + 1)/ (float)column;
				final float top		= (float)y 		/ (float)row;
				final float bottom	= (float)(y + 1)/ (float)row;
				
				float[] crop = new float[] {
					left,	top,
					right,	top,
					left,	bottom,
					right,	bottom
				};
				
				mImages[(y * column) + x] = new GLTiledTexture(mainTexture, crop);
		}
		//Set delay
		mDelay = delay;
		if (mDelay > 0) mAnimating = true;
	}

	public Sprite(GLTiledTexture[] images, int xPos, int yPos, long delay) {
		//Default
		this();

		//Set position
		mX		= xPos;
		mY		= yPos;
		mImages	= images;
		
		Log.d(TAG, "making sprite " + images[0].Texture.Resource + " loaded ? " + images[0].Texture.Loaded);
		
		final float left 	= images[0].Crop[0];
		final float right 	= images[0].Crop[2];
		final float top		= images[0].Crop[5];
		final float bottom	= images[0].Crop[1];
		
		mWidth	= (int)(images[0].Texture.Width * (right - left));
		mHeight	= (int)(images[0].Texture.Height * (bottom - top));

		//Set delay
		mDelay = delay;
		if (mDelay > 0) mAnimating = true;
	}

	public static void readTintData() {
		//Instantiate hashtable
		sTints = new HashMap<Integer, Integer>();

		//Read xml
		Node root = XMLReader.instance().parseXML(Utilities.TINTDATA_FILE);

		//For each child
		int childCount = root.getChildNodes().getLength();
		for (int i = 0; i < childCount; i++) {
			//Default
			int index = -1;
			int color = 0xffffffff;
			Node child = root.getChildNodes().item(i);
			if (child.getNodeType() == Node.TEXT_NODE) continue;

			//Check child name
			if (child.getNodeName().equals("tint")) {
				//Get node
				index	= Integer.parseInt(child.getAttributes().getNamedItem("index").getNodeValue());

				//Get color
				int grandChildCount = child.getChildNodes().getLength();
				for (int j = 0; j < grandChildCount; j++) {
					//If color
					Node grandChild = child.getChildNodes().item(j);
					if (grandChild.getNodeType() == Node.TEXT_NODE) continue;
					
					if (grandChild.getNodeName().equals("color")) {
						//Get data
						int A = Integer.parseInt(grandChild.getAttributes().getNamedItem("a").getNodeValue());
						int R = Integer.parseInt(grandChild.getAttributes().getNamedItem("r").getNodeValue());
						int G = Integer.parseInt(grandChild.getAttributes().getNamedItem("g").getNodeValue());
						int B = Integer.parseInt(grandChild.getAttributes().getNamedItem("b").getNodeValue());

						//Set color
						color = (A << 24) | (R << 16) | (G << 8) | B;
						Log.d(TAG, "Tint data A " + A + " R " + R + " G" + G + " B " + B);
						Log.d(TAG, "color " + color);
					}
				}

				//Check index
				if (index >= 0) {
					sTints.put(new Integer(index), new Integer(color));
				}
			}
		}
	}

	public static int getTint(int index) {
		//Default tint
		int Tint = 0xffffffff;

		//Find tint
		if (sTints != null) {
			Integer TintInteger = (Integer)sTints.get(new Integer(index));
			if (TintInteger != null) Tint = TintInteger.intValue();
		}

		//Return tint
		return Tint;
	}

	public static int[] getTints() {
		//1 is null
		if (sTints == null) return new int[]{0xffffffff};

		//Prepare variable
		int[] Tints = new int[sTints.size() + 1];
		Tints[0]	= 0xffffffff;

		//Read
		for (int i = 0; i < sTints.size(); i++)
			Tints[i + 1] = Sprite.getTint(i + 1);

		//return tints
		return Tints;
	}

	public int getWidth() {
		return mWidth;
	}

	public int getHeight() {
		return mHeight;
	}

	public void setAnimating(boolean animating) {
		//Set animation
		mAnimating = true;
	}

	public void setFrame(int frame) {
		//Set frame
		mFrame = frame;

		//Correct frame
		if (mFrame < 0)				mFrame = 0;
		if (mFrame > mImages.length)mFrame = mImages.length - 1;
	}

	public void setPosition(int x, int y) {
		mX = x;
		mY = y;
	}

	public void setTilePosition(int x, int y, int offsetX, int offsetY) {
		//Set position
		mX = (x * Utilities.TILE_WIDTH)  + offsetX;
		mY = (y * Utilities.TILE_HEIGHT) + offsetY;
	}

	public void addTint(int color, long delay) {
		//Add new tint
		mTints.add(new Tint(color, delay));
	}

	public void update(long time) {
		//If animating
		if (mAnimating) {
			//Increase timer
			mTimer += time;

			//If more than delay
			if (mTimer >= mDelay) {
				//Reset
				mTimer -= mDelay;

				//Next frame
				mFrame++;
				if (mFrame >= mImages.length) mFrame = 0;
			}
		}

		for (int i = 0; i < mTints.size(); i++) {
			mTints.get(i).update(time);
			if (!mTints.get(i).isActive()) mDeletedTints.add(mTints.get(i));
		}

		//Kill dead tints
		for (int i = 0; i < mDeletedTints.size(); i++) mTints.remove(mDeletedTints.get(i));
		mDeletedTints.clear();
	}

	public void draw(GL10 gl) {
		//Get last tint
		
		/// TODO wtf with this current tint?
		int current = 0;
		if (!mTints.isEmpty()) current = mTints.get(mTints.size() - 1).getTint();
		
		//Draw
		mImages[mFrame].Texture.Tint = getTint(current);
		GameRenderer.instance().draw(gl, 
				mImages[mFrame].Texture, 
				mImages[mFrame].Crop,
				mX, mY,
				mWidth, mHeight,
				Utilities.SPRITE_DEPTH);
	}
	
	//Tint colors
	protected static HashMap<Integer, Integer> sTints;

	//Data
	protected int		mX;
	protected int		mY;
	protected int		mWidth;
	protected int		mHeight;
	protected GLTiledTexture[]mImages;

	//Animation
	protected int		mFrame;
	protected long		mDelay;
	protected long		mTimer;
	protected ArrayList<Tint>	mTints, mDeletedTints;
	protected boolean	mAnimating;
}
